-
Notifications
You must be signed in to change notification settings - Fork 409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor converting type expressions to typerefs and ranges #7274
Conversation
0b512d0
to
2572338
Compare
# If this is an intersection type, this would be a set of | ||
# intersection elements. | ||
intersection: typing.Optional[typing.FrozenSet[TypeRef]] = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It weirds me out a little if we aren't going to track that a type is an intersection in the TypeRef, even when it is one in the schema.
This might not actually matter though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit odd, but the typeref doesn't exactly map onto types anyways
if t.is_union_type(schema) or t.is_intersection_type(schema): | ||
normalized: s_utils.NormalizedTypeExpr = ( | ||
s_utils.NormalizedTypeExpr.create(t, schema=schema) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does normalizing help here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All normalization stuff removed.
edb/ir/typeutils.py
Outdated
# Always include children and ancestors for complex types | ||
ancestor_types = normalized.get_ancestors(schema=schema) | ||
child_types = normalized.get_descendants(schema=schema) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this new behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The issue is in _find_rvar_in_intersection_by_typeref
and type_contains
. When compiling the intersection, the typeref is used to find an appropriate rvar using the concept of "containment". With only simple unions or intersections this is straightforward enough.
When dealing with an intersection with potentially type expressions on either side, figuring out whether a typeref "contains" another becomes harder since the schema is not available.
For example, with R
= (A | B) & C
has the ancestors C
and Obj
. However, L
= A | B
should count as "containing" R
despite not being a direct ancestor. The approach taken here to solve this is to check that L.children
is a superset of R.children
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More cases detailed in type_contains
16930f4
to
5e114aa
Compare
# filter out subclasses | ||
expanded_types = { | ||
type | ||
for type in expanded_types | ||
if not any( | ||
type is not other and type.issubclass(schema, other) | ||
for other in expanded_types | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? I guess it helps us not always require union_is_exhaustive
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. It also makes reading the sql easier too :)
edb/schema/utils.py
Outdated
def expand_type_expr_ancestors( | ||
type: s_types.Type, | ||
schema: s_schema.Schema, | ||
) -> set[s_types.Type]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This weirds me out some
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... What do you mean? The implementation of the function or rather its existence?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existence, I think
3be2fea
to
a8de853
Compare
a8de853
to
759123d
Compare
Remove special intersection behaviour and resolve all type expressions to produce a non-overlapping union of types. This will be helpful when implementing type expressions.
Currently, it's really only possible to create unions or intersections of unions, so this change should not affect behaviour.
Uses of both
typeref.union
andtyperef.intersection
:process_set_as_agg_expr
should be serializedUses of
typeref.union
only:Typeref ranges
The current behaviour is:
union ALL
join on id
The proposed behaviour is:
union ALL
In theory, it should be possible to convert a type expression into an intersection of non-overlapping unions:
~A
expressions)This can then be converted into SQL which matches the CNF. However, since the underlying types are implemented as views the query will be slower than just using the types directly.
One more performance consideration is that this new implementation will get all ancestors and children of a typeref. This may have performance impact on the compiler side.
Effect of changes
Non-overlapping union
select Ba is CBa | Bb
No changes:
Overlapping union
select Ba is Ba | Bb
No changes:
Simple intersection
select Ba [is Bb]
Intersection changed to non-overlapping union.
On
master
:On branch:
Complex intersection
select {Ba, Bb} [is Bc]
Join target becomes a non-overlapping union. There is probably room for further optimization in
process_set_as_path_type_intersection
.On
master
:On branch: